package top.as.sean.biz.system.impl;

import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import top.as.sean.biz.system.IDataDict;
import top.as.sean.common.constant.Constant;
import top.as.sean.common.constant.RedisConstant;
import top.as.sean.common.exception.GlobalException;
import top.as.sean.common.id.SnowflakeId;
import top.as.sean.common.response.RespStatus;
import top.as.sean.dao.dto.system.DictTypeEdit;
import top.as.sean.dao.dto.system.DictTypePage;
import top.as.sean.dao.dto.system.DictTypeAdd;
import top.as.sean.dao.dto.system.DictValueAdd;
import top.as.sean.dao.dto.system.DictValueEdit;
import top.as.sean.dao.dto.system.DictValuePage;
import top.as.sean.dao.entity.pojo.system.DataDict;
import top.as.sean.dao.mapper.system.DataDictMapper;

import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 数据字典
 *
 * @author: ArchieSean
 * @create: 2022/11/6
 */
@Slf4j
@Service
public class DataDictImpl extends ServiceImpl<DataDictMapper, DataDict> implements IDataDict {
    /**
     * 编辑数据字典值
     *
     * @param dto 入参
     * @return boolean
     */
    @Override
    public Boolean editValue(DictValueEdit dto) {
        DataDict dataDict = this.lambdaQuery()
                .eq(DataDict::getId, dto.getId())
                .one();
        if (ObjUtil.isEmpty(dataDict)) {
            throw new GlobalException(RespStatus.DICT_DATA_NOT_FOUND);
        }
        if (StringUtils.hasLength(dto.getCode()) && !dto.getCode().equals(dataDict.getCode())
                && validCode(dataDict.getParentCode() + RedisConstant.UNDER_LINE + dto.getCode())
        ) {
            throw new GlobalException(RespStatus.DICT_VALUE_CODE_EXIST);
        }
        DataDict updateValue = new DataDict();
        BeanUtils.copyProperties(dto, updateValue);
        return updateById(updateValue);
    }

    /**
     * 查询数据字典值分页
     *
     * @param dto 入参
     * @return page
     */
    @Override
    public Page<DataDict> getValuePage(DictValuePage dto) {
        Page<DataDict> page = new Page<>();
        return this.lambdaQuery()
                .likeRight(StringUtils.hasLength(dto.getCode()), DataDict::getCode, dto.getCode())
                .likeRight(StringUtils.hasLength(dto.getDictName()), DataDict::getDictName, dto.getDictName())
                .eq(ObjUtil.isNotEmpty(dto.getParentId()), DataDict::getParentId, dto.getParentId())
                .eq(StringUtils.hasLength(dto.getStatus()), DataDict::getStatus, dto.getStatus())
                .orderByAsc(DataDict::getSortNumber)
                .page(page);
    }

    /**
     * 新增数据字典值
     *
     * @param dto 入参
     * @return boolean
     */
    @Override
    public Boolean addValue(DictValueAdd dto) {
        DataDict dictType = this.lambdaQuery().eq(DataDict::getId, dto.getParentId()).one();
        if (ObjUtil.isEmpty(dictType)) {
            throw new GlobalException(RespStatus.DICT_TYPE_NOT_FOUND);
        }
        //校验字典编码+字典类型编码是否存在
        boolean flag = this.lambdaQuery()
                .eq(DataDict::getCode, dto.getCode())
                .eq(DataDict::getParentCode, dictType.getDictCode())
                .exists();
        if (flag) {
            log.error("新增数据字典值编码已存在，新增失败！");
            throw new GlobalException(RespStatus.DICT_VALUE_CODE_EXIST);
        }
        //新增字典值
        DataDict insertDict = new DataDict();
        BeanUtils.copyProperties(dto, insertDict);
        //设置字典值整体编码： 字典类型编码_字典值编码
        insertDict.setDictCode(dictType.getDictCode() + RedisConstant.UNDER_LINE + dto.getCode());
        insertDict.setId(SnowflakeId.createId());
        insertDict.setParentId(dictType.getId());
        insertDict.setParentCode(dictType.getDictCode());
        return save(insertDict);
    }

    /**
     * 编辑数据字典类型
     *
     * @param dto 入库
     * @return boolean
     */
    @Override
    public Boolean editType(DictTypeEdit dto) {
        DataDict dict = this.lambdaQuery()
                .eq(DataDict::getId, dto.getId())
                .one();
        if (!Optional.ofNullable(dict).isPresent()) {
            throw new GlobalException(RespStatus.DICT_TYPE_NOT_FOUND);
        }
        //是否是字典类型更改
        if (StringUtils.hasLength(dto.getDictCode()) && !dto.getDictCode().equals(dict.getDictCode())
                && !validCode(dict.getDictCode())) {
            log.error("数据字典类型编码已存在，更新失败！");
            throw new GlobalException(RespStatus.DICT_TYPE_CODE_EXIST);
        }
        DataDict updateDict = new DataDict();
        BeanUtils.copyProperties(dto, updateDict);
        return updateById(updateDict);
    }

    /**
     * 删除字典类型
     *
     * @param ids 字典id
     * @return boolean
     */
    @Override
    public Boolean removeBatchTypes(List<Long> ids) {
        return this.remove(Wrappers.lambdaQuery(DataDict.class)
                .in(!CollectionUtils.isEmpty(ids), DataDict::getId, ids)
                .or()
                .in(!CollectionUtils.isEmpty(ids), DataDict::getParentId, ids)
        );
    }

    /**
     * @param dto 入参
     * @return boolean
     */
    @Override
    public Boolean addType(DictTypeAdd dto) {
        //校验字典编码是否可用
        Boolean validCode = validCode(dto.getDictCode());
        if (validCode) {
            throw new GlobalException(RespStatus.DICT_TYPE_CODE_EXIST);
        }
        DataDict dict = new DataDict();
        BeanUtils.copyProperties(dto, dict);
        dict.setId(SnowflakeId.createId());
        return this.save(dict);
    }

    /**
     * 校验字典编码是否存在
     *
     * @param dictCode 字典编码
     * @return boolean
     */
    private Boolean validCode(@NotNull String dictCode) {
        return this.lambdaQuery()
                .eq(DataDict::getDictCode, dictCode)
                .exists();
    }

    /**
     * 字典类型分页
     *
     * @param dto 入参
     * @return page
     */
    @Override
    public Page<DataDict> getTypePage(DictTypePage dto) {
        Page<DataDict> page = new Page<>(dto.getPageNum(), dto.getPageSize());
        this.lambdaQuery()
                .like(StringUtils.hasLength(dto.getDictName()), DataDict::getDictName, dto.getDictName())
                .like(StringUtils.hasLength(dto.getDictCode()), DataDict::getDictCode, dto.getDictCode())
                .eq(StringUtils.hasLength(dto.getStatus()), DataDict::getStatus, dto.getStatus())
                .eq(DataDict::getParentId, BigDecimal.ZERO.intValue())
                .page(page);
        return page;
    }

    /**
     * 根据数据字典编码获取数据字典值
     *
     * @param dictCode 数据字典编码
     * @return map
     */
    @Override
    public Map<String, String> getDictData(String dictCode) {
        List<DataDict> list = this.lambdaQuery()
                .eq(DataDict::getParentCode, dictCode)
                .eq(DataDict::getStatus, Constant.DictEnum.ENABLE.getCode())
                .list();
        if (CollectionUtils.isEmpty(list)) {
            log.error("没有对应的数据字典值--->{}", dictCode);
            throw new GlobalException(RespStatus.DICT_DATA_NOT_FOUND);
        }
        return list.stream().collect(Collectors.toMap(DataDict::getCode, DataDict::getDictName));
    }

    /**
     * 删除数据字典值
     *
     * @param id id
     * @return boolean
     */
    @Override
    public Boolean delValue(Long id) {
        return this.removeById(id);
    }
}
